﻿namespace PauloMorgado.Phone.Services.Reactive
{
    using System;
    using System.Device.Location;
    using System.Reactive.Linq;

    public class GeoCoordinateReactiveService : IGeoCoordinateReactiveService, IDisposable
    {
        private readonly GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher();

        public GeoCoordinateReactiveService()
        {
            this.StatusObservable = Observable
                .FromEventPattern<GeoPositionStatusChangedEventArgs>(
                    handler => geoCoordinateWatcher.StatusChanged += handler,
                    handler => geoCoordinateWatcher.StatusChanged -= handler)
                .Select(ep => ep.EventArgs.Status);

            this.PositionObservable = Observable
                .FromEventPattern<GeoPositionChangedEventArgs<GeoCoordinate>>(
                    handler => geoCoordinateWatcher.PositionChanged += handler,
                    handler => geoCoordinateWatcher.PositionChanged -= handler)
                .Select(ep => ep.EventArgs.Position);
        }

        ~GeoCoordinateReactiveService()
        {
            Dispose(false);
        }

        public GeoPositionAccuracy DesiredAccuracy
        {
            get { return this.geoCoordinateWatcher.DesiredAccuracy; }
        }

        public double MovementThreshold
        {
            get { return this.geoCoordinateWatcher.MovementThreshold; }
            set { this.geoCoordinateWatcher.MovementThreshold = value; }
        }

        public GeoPosition<GeoCoordinate> Position
        {
            get { return this.geoCoordinateWatcher.Position; }
        }

        public GeoPositionStatus Status
        {
            get { return this.geoCoordinateWatcher.Status; }
        }

        public GeoPositionPermission Permission
        {
            get { return this.geoCoordinateWatcher.Permission; }
        }

        public IObservable<GeoPositionStatus> StatusObservable { get; private set; }

        public IObservable<GeoPosition<GeoCoordinate>> PositionObservable { get; private set; }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public void Start()
        {
            this.geoCoordinateWatcher.Start();
        }

        public void Start(bool suppressPermissionPrompt)
        {
            this.geoCoordinateWatcher.Start(suppressPermissionPrompt);
        }

        public void Stop()
        {
            this.geoCoordinateWatcher.Stop();
        }

        public bool TryStart(bool suppressPermissionPrompt, TimeSpan timeout)
        {
            return this.geoCoordinateWatcher.TryStart(suppressPermissionPrompt, timeout);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.geoCoordinateWatcher != null)
                {
                    this.geoCoordinateWatcher.Dispose();
                }
            }
        }
    }
}
